package com.ct.ecommerce.idgen.core;

import java.util.Arrays;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import lombok.Data;


/**
 * 双buffer
 * @author changtong
 * @date 2021-50-20
 */
@Data
public class SegmentBuffer {

    private String key;
    /**
     * 双buffer
     */
    private Segment[] segments;
    /**
     * 当前的使用的segment的index
     */
    private volatile int currentPos;
    /**
     * 下一个segment是否处于可切换状态
     */
    private volatile boolean nextReady;
    /**
     * 是否初始化完成
     */
    private volatile boolean initOk;
    /**
     * 线程是否在运行中
     */
    private final AtomicBoolean threadRunning;

    private final ReadWriteLock lock;

    private volatile int step;

    private volatile int minStep;

    private volatile long updateTimestamp;

    public Segment getCurrent() {
        return segments[currentPos];
    }

    public SegmentBuffer() {
        segments = new Segment[]{new Segment(this), new Segment(this)};
        currentPos = 0;
        nextReady = false;
        initOk = false;
        threadRunning = new AtomicBoolean(false);
        lock = new ReentrantReadWriteLock();
    }

    public Lock rLock() {
        return lock.readLock();
    }

    public Lock wLock() {
        return lock.writeLock();
    }

    public int nextPos() {
        return (currentPos + 1) & 1;
    }

    public void switchPos() {
        currentPos = nextPos();
    }

    @Override
    public String toString() {
        StringJoiner s = new StringJoiner("", "SegmentBuffer{", "}");
        return s.add("key:").add(key)
            .add(",segments:").add(Arrays.toString(segments))
            .add(",currentPos:").add(String.valueOf(currentPos))
            .add(",nextReady:").add(String.valueOf(nextReady))
            .add(",initOk:").add(String.valueOf(initOk))
            .add(",threadRunning:").add(String.valueOf(threadRunning))
            .add(",step:").add(String.valueOf(step))
            .add(",minStep:").add(String.valueOf(minStep))
            .add(",updateTimestamp:").add(String.valueOf(updateTimestamp))
            .toString();
    }
}